/**
 * 
 */
package edu.fiu.cis.selfhealingdisk;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * @author vanvorst
 * 
 */
public class IOTrace {
	private final List<IORequest> requests = new ArrayList<IORequest>();
	private int index = 0;
	private final boolean readOnly;
	private long maxBlock = 0;
	private long minTime = -1;

	/**
	 * @param file
	 * @throws IOException
	 */
	public IOTrace(final String file) throws IOException {
		readOnly = true;
		final BufferedReader br = new BufferedReader(new InputStreamReader(
				new DataInputStream(new FileInputStream(file))));
		String str = null;
		while ((str = br.readLine()) != null) {
			IORequest r=IORequest.parseIORequest(str.trim());
			requests.add(r);
			if (r.getLba() > maxBlock) {
				maxBlock = r.getLba();
			}
			if ((minTime == -1) || (r.getRequestTime() < minTime)) {
				minTime = r.getRequestTime();
			}
		}
		br.close();
		
		for (final IORequest r : requests) {
			r.setRequestTime(r.getRequestTime()-minTime);
		}
		
	}

	/**
	 * @param file
	 */
	public IOTrace() {
		readOnly = false;
	}

	/**
	 * Reset the Trace so next() returns the first io request
	 */
	public void reset() {
		index = 0;
	}

	/**
	 * Returns the next io request and null when no there are no more requests
	 * 
	 * @return
	 */
	public final IORequest next() {
		if (index >= requests.size()) {
			return null;
		}
		return requests.get(index++);
	}

	
	/**
	 * Returns the next io request and null when no there are no more requests
	 * 
	 * @return
	 */
	public final IORequest peek() {
		if (index >= requests.size()) {
			return null;
		}
		return requests.get(index);
	}
	
	
	/**
	 * Add the request r to the trace at index i.
	 * 
	 * @throws IllegalStateException
	 *             if you call this on a IOtrace built from a file.
	 */
	public final void addIORequest(final int i, final IORequest r)
			throws IllegalStateException {
		if (readOnly) {
			throw new IllegalStateException(
					"Adding requests this this trace is not allowed!");
		}
		if (r.getLba() > maxBlock) {
			maxBlock = r.getLba();
		}
		if ((minTime == -1) || (r.getRequestTime() < minTime)) {
			minTime = r.getRequestTime();
		}
		requests.add(i, r);
	}

	/**
	 * Add the request r to the end of the trace.
	 * 
	 * @throws IllegalStateException
	 *             if you call this on a IOtrace built from a file.
	 */
	public final void addIORequest(final IORequest r)
			throws IllegalStateException {
		if (readOnly) {
			throw new IllegalStateException(
					"Adding reuests this this trace is not allowed!");
		}
		if (r.getLba() > maxBlock) {
			maxBlock = r.getLba();
		}
		if ((minTime == -1) || (r.getRequestTime() < minTime)) {
			minTime = r.getRequestTime();
		}
		requests.add(r);
	}

	/**
	 * @return
	 */
	public final long getMaxBlockNumber() {
		return maxBlock;
	}

	/**
	 * Return the timestamp from the first request
	 * @return the timestamp from the first request
	 */
	public final long getMinTime() {
		return this.minTime;
	}
	
	/**
	 * @param file
	 * @throws IOException
	 */
	public void saveInBlkParseFormat(final String file, final boolean includeServiceTime) throws IOException {
		final FileWriter f = new FileWriter(file);
		for (final IORequest r : requests) {
			f.write(r.asBlkParseEntry(includeServiceTime) + "\n");
		}
		f.close();
	}

	/**
	 * @param file
	 * @throws IOException
	 */
	public void saveInDiskSimFormat(final String file, final boolean includeServiceTime) throws IOException {
		final FileWriter f = new FileWriter(file);
		for (final IORequest r : requests) {
			f.write(r.asDiskSimIOEntry(minTime,includeServiceTime) + "\n");
		}
		f.close();
	}
}
